home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
magazine
/
pcmagazi
/
1988
/
07
/
touch.asm
next >
Wrap
Assembly Source File
|
1988-04-11
|
30KB
|
612 lines
TITLE TOUCH
Page 60,132
;--------------------------------------------------------------------
; TOUCH - Set the time/date entry for a file.
; PC Magazine - Michael J. Mefford
;--------------------------------------------------------------------
_TEXT SEGMENT PUBLIC 'CODE' ;********************************;
ASSUME CS:_TEXT,DS:_TEXT ;* *;
;* Requires MASM 2.0 or later *;
ORG 80H + 22 ;* Remember to EXE2BIN *;
FILE_TIME DW ? ;* *;
FILE_DATE DW ? ;********************************;
FILE_SIZE_LOW DW ?
FILE_SIZE_HIGH DW ?
FILE_NAME DB ?
ORG 100H
START: JMP MAIN
CR EQU 13
LF EQU 10
CTRL_Z EQU 26
SPACE EQU 32
; DATA AREA
; ---------
DB CR,SPACE,SPACE,SPACE,CR,LF
COPYRIGHT DB "TOUCH 1.0 (c) 1988 Ziff Communications Co.",CR,LF
PROGRAMMER DB "PC Magazine ",254," Michael J. Mefford",CR,LF,"$"
SYNTAX DB CR,LF
DB CR,LF,"Syntax: TOUCH filespec [/D date] [/T time]"
DB CR,LF,"date = month-day-year"
DB CR,LF,"time = hour[:minutes[:seconds]]"
DB CR,LF,"Default is system date and time."
CR_LF DB CR,LF,"$"
DB CTRL_Z
DATE_FLAG EQU 1
TIME_FLAG EQU 2
CURRENT_DISK DB ?
PATH_END DW ?
SWITCH_FLAG DB 0
SWITCH_DATE DW 0
SWITCH_TIME DW 0
SYSTEM_DATE DW ?
SYSTEM_TIME DW ?
TOUCH_DATE DW ?
TOUCH_TIME DW ?
SYNTAX_MSG DB "Invalid parameter$"
NOT_FOUND_MSG DB "File not found$"
DELIMITERS DB ":-/"
; CODE AREA
; ---------
;------------------------------------------------------------------------;
; First task is to save the current drive and directory defaults. ;
; We will be changing the defaults and wish to restore them on exit. ;
; The system date and time is retrieved, compressed, and stored to stamp ;
; the file if no switch request found. Carriage return linefeed combo ;
; sent to display to put air between DOS prompt and TOUCH's messages. ;
;------------------------------------------------------------------------;
MAIN PROC NEAR
CLD ;String moves forward.
MOV AH,9
MOV DX,OFFSET COPYRIGHT
INT 21H
MOV AH,19H ;Get current drive
INT 21H
MOV CURRENT_DISK,AL ; and save.
MOV BYTE PTR CURRENT_DIR,"\" ;DOS doesn't preface directory
MOV SI,OFFSET CURRENT_DIR + 1 ; with slash so we must.
XOR DL,DL
MOV AH,47H ;Get current directory.
INT 21H
MOV AH,2AH ;Get current date
INT 21H
CALL CONVERT_DATE ; compress
MOV SYSTEM_DATE,DX ; and store.
MOV AH,2CH ;Get current time and do same.
INT 21H
CALL CONVERT_TIME
MOV SYSTEM_TIME,DX
MOV DX,OFFSET CR_LF ;Send carriage return linefeed
MOV AH,9 ; to display just to make our
INT 21H ; output pretty.
;-----------------------------------------------------------------------;
; Parse the command line for date or time switches. If found, compress ;
; decimal number to hex format required by DOS to set date and time. ;
;-----------------------------------------------------------------------;
MOV SI,81H ;Point to command line parameter.
FIND_SWITCH: LODSB ;Get a byte.
CMP AL,CR ;Carriage return marks end.
JZ FILESPEC ;If end, done here.
CMP AL,"/" ;Is it a switch character?
JNZ FIND_SWITCH ;If no, next byte.
LODSB ;Else, retrieve switch.
CMP AL,CR ;Did user omit character?
JZ FILESPEC ;If yes, done here.
AND AL,5FH ;Else, capitalize.
CMP AL,"D" ;Is it date switch?
JNZ CK_TIME ;If no, check if time.
OR SWITCH_FLAG,DATE_FLAG ;Else, flag that date included.
CALL PARSE_LEADING ;Parse off leading delimiters.
CALL GET_NUMBER ;Get first number.
JZ BAD_PARAMETER ;Was it a zero or no number?
MOV DH,BL ;If yes, exit, else store month.
CALL GET_NUMBER ;Get next number.
JZ BAD_PARAMETER ;Was it zero?
MOV DL,BL ;If yes, exit, else store day.
CALL GET_NUMBER ;Get last number.
JZ BAD_PARAMETER ;Was it zero?
MOV CX,BX ;If yes, exit, else store year.
CALL CONVERT_DATE ;Convert decimal to compressed
MOV SWITCH_DATE,DX ; hex number and store.
JMP SHORT FIND_SWITCH ;Check for another switch.
CK_TIME: CMP AL,"T" ;Is there a time switch?
JNZ FIND_SWITCH ;If no, check next byte.
OR SWITCH_FLAG,TIME_FLAG ;Else, flag that time included.
CALL PARSE_LEADING ;Handle same as date.
CALL GET_NUMBER
MOV DH,BL ;Store hour in DH.
CALL GET_NUMBER
MOV DL,BL ;Store minutes in DL.
CALL GET_NUMBER
MOV CX,DX ;Store hour and minutes in CX.
MOV DH,BL ;Store seconds in DH.
CALL CONVERT_TIME ;Convert
MOV SWITCH_TIME,DX ; and store.
JMP SHORT FIND_SWITCH ;Check for next switch.
;-----------------------------------------;
; Lily pad for short jumps to error exit. ;
;-----------------------------------------;
BAD_PARAMETER: JMP SYNTAX_EXIT ;Error jumping address.
;------------------------------------------------------------------;
; Parse drive and/or path delimiters. Convert filespec to ASCIIZ. ;
; If drive delimiter found (:), change to requested drive. ;
;------------------------------------------------------------------;
FILESPEC: MOV SI,81H ;Point to command line parameter.
CALL PARSE_LEADING ;Parse off leading delimiters.
PUSH SI ;Save start of filename.
XOR BX,BX ;Use BX as path specifier flag.
FIND_END: LODSB ;Get a byte.
CMP AL,":" ;Is it a drive delimiter?
JNZ CK_PATH ;If no, check if path delimiter.
MOV DL,[SI-2] ;Else, retrieve drive specifier.
AND DL,5FH ;Capitalize.
SUB DL,"A" ;Convert to DOS format.
MOV AH,0EH ;Change drive.
INT 21H
MOV BX,SI ;Save as possible filename start.
JMP SHORT FIND_END
CK_PATH: CMP AL,"\" ;Is it a path delimiter?
JNZ CK_DELIMITER ;If no, check switch character.
MOV BX,SI ;Else, save as possible filename.
CK_DELIMITER: CMP AL,"/" ;Is it a switch delimiter?
JZ FOUND_END ;If yes, end of filespec.
CMP AL,SPACE ;Is it above space character?
JA FIND_END ;If yes, continue until find end.
FOUND_END: MOV BYTE PTR [SI-1],0 ;Else, convert to ASCIIZ.
;------------------------------------------------------------------;
; Save the working default directory so we can restore it on exit. ;
; If path was found, change to requested directory. ;
;------------------------------------------------------------------;
MOV BYTE PTR WORKING_DIR,"\" ;DOS doesn't preface directory
MOV SI,OFFSET WORKING_DIR + 1 ; with slash so we must.
XOR DL,DL
MOV AH,47H ;Get current directory
INT 21H ; of working drive.
POP DX ;Retrieve filespec start.
OR BX,BX ;Was there a path specifier?
JZ FIND_FILE ;If no, done here.
CMP BYTE PTR [BX-1],":" ;Was it a drive specifier only?
JZ FIND_FILE ;If yes, done here.
PUSH BX ;Else, save as filename start.
CMP BYTE PTR [BX-2],":" ;Was it "d:\"?
JZ CHANGE_DIR ;If yes, no adjust.
CMP BYTE PTR [BX-2],SPACE ;Was it plain root "\"?
JBE CHANGE_DIR ;If yes, no adjust.
DEC BX ;Else point to path delimiter.
CHANGE_DIR: PUSH [BX] ;Save first byte of filename.
MOV BYTE PTR [BX],0 ;Temporary zero so ASCIIZ path.
MOV AH,3BH ;Change directory.
INT 21H
POP [BX] ;Restore first byte of filename.
POP DX ;Retrieve filename pointer.
;------------------------------------------------------------------------;
; Ready for business. Find the file and get a filehandle by opening the ;
; file for reading. If no matching filename is found, exit with error ;
; message. If no switch characters were found, then update file with ;
; system date and time. Else, touch with requested value. If only one ;
; switch request was made, don't change the other. Display results. ;
;------------------------------------------------------------------------;
FIND_FILE: MOV CX,7 ;Attribute of all files.
MOV AH,4EH ;Find first matching file.
INT 21H
JNC TOUCH_FILE ;If found, change date/time.
MOV DX,OFFSET NOT_FOUND_MSG ;Else, display error message
JMP SHORT MESSAGE_EXIT ; and exit.
FIND_NEXT: MOV AH,4FH ;Find next matching file.
INT 21H
JC GOOD_EXIT ;If failed, we're done.
TOUCH_FILE: MOV DX,OFFSET FILE_NAME ;Else, open file for reading
MOV AX,3D00H ; to get a filehandle.
INT 21H
MOV BX,AX ;Filehandle needs to be in BX.
MOV CX,SYSTEM_TIME ;Assume request to update
MOV DX,SYSTEM_DATE ; to system date and time.
MOV AL,SWITCH_FLAG ;Retrieve the switch flag.
CMP AL,0 ;Was there a switch?
JZ SET_DATE_TIME ;If no, assumed right.
MOV CX,SWITCH_TIME ;Else, assume it a time request.
TEST AL,TIME_FLAG ;Was there a time switch?
JNZ DO_DATE ;If yes, assumed right.
MOV CX,FILE_TIME ;Else, use file's time.
DO_DATE: MOV DX,SWITCH_DATE ;Assume there was a date request.
TEST AL,DATE_FLAG ;Was there a date switch?
JNZ SET_DATE_TIME ;If yes, assumed right.
MOV DX,FILE_DATE ;Else, use file's date.
SET_DATE_TIME: MOV TOUCH_TIME,CX ;Save date and time for
MOV TOUCH_DATE,DX ; display purposes.
MOV AX,5701H ;Set file's date and time.
INT 21H
JC SYNTAX_EXIT ;If failed, exit with message.
CLOSE_FILE: MOV AH,3EH ;Close the file.
INT 21H
CALL DISPLAY_NAME ;Display complete stats of file.
JMP SHORT FIND_NEXT ;Find next file.
;--------------------------------------------------------------------;
; Display error message and TOUCH syntax if necessary. Restore ;
; working directory and default drive and directory. Exit with ;
; error code of one if problem; error code of zero if all went well. ;
;--------------------------------------------------------------------;
SYNTAX_EXIT: MOV DX,OFFSET SYNTAX_MSG ;Display "Invalid parameters".
MESSAGE_EXIT: MOV AH,9
INT 21H
MOV DX,OFFSET SYNTAX ;Display TOUCH syntax message.
MOV AH,9
INT 21H
MOV AL,1 ;Exit with error code of 1.
JMP SHORT EXIT
GOOD_EXIT: XOR AL,AL ;Exit with error code of 0.
EXIT: PUSH AX ;Save error code.
MOV DX,OFFSET WORKING_DIR ;Restore working directory.
MOV AH,3BH
INT 21H
MOV DL,CURRENT_DISK ;Restore default drive.
MOV AH,0EH
INT 21H
MOV DX,OFFSET CURRENT_DIR ;Restore default drive directory.
MOV AH,3BH
INT 21H
POP AX ;Retrieve error code.
MOV AH,4CH
INT 21H ;Terminate.
MAIN ENDP
;***************;
;* SUBROUTINES *;
;***************;
;---------------------------------------------------;
; INPUT ;
; CX = Year (1980 - 2099) ;
; DH = Month (1 - 12) ;
; DL = Day (1 - 31) ;
; ;
; OUTPUT ;
; DX = compressed date in directory entry format. ;
; ;
; < DH > < DL > ;
; y y y y y y y m m m m d d d d d ;
; ;
; y = year (0 - 119) ;
; m = month (1 - 12) ;
; d = day (1 - 31) ;
; ;
; BX, CX destroyed. ;
;---------------------------------------------------;
CONVERT_DATE PROC NEAR
SUB CX,80 ;Compress year.
CMP CX,1900 ;Did user abbreviate year?
JB SAVE_MONTH ;If yes, OK.
SUB CX,1900 ;Else, subtract century part.
SAVE_MONTH: MOV BL,DH ;Store month in BL.
XOR BH,BH ;Zero in high half.
SHL CL,1 ;Right justify year.
MOV DH,CL ;Store in DH.
MOV CL,5 ;Shift month left 5 bits.
SHL BX,CL
OR DX,BX ;Add year and month to days.
RET
CONVERT_DATE ENDP
;---------------------------------------------------;
; INPUT ;
; CH = Hour (0 - 23) ;
; CL = Minutes (0 - 59) ;
; DH = Seconds (0 - 59) ;
; ;
; OUTPUT ;
; DX = compressed time in directory entry format. ;
; ;
; < DH > < DL > ;
; h h h h h m m m m m m x x x x x ;
; ;
; h = hour (0 - 23) ;
; m = minutes (0 - 59) ;
; x = two-second increments (0 - 28) ;
; ;
; BX, CX destroyed. ;
;---------------------------------------------------;
CONVERT_TIME PROC NEAR
MOV BX,CX ;Store hour and min. in BX so we
MOV CL,9 ; can use CL as shift register.
SHR DX,CL ;Right justify; divide secs by 2.
MOV CL,3 ;Justify left hour.
SHL BH,CL
MOV DH,BH ;Store hour in DH.
MOV CL,5
SHL BX,CL ;Justify minutes.
OR DX,BX ;Add minutes to hour and seconds.
RET
CONVERT_TIME ENDP
;----------------------------------------;
; INPUT ;
; DS:SI points to ASCII number string. ;
; ;
; OUTPUT ;
; BX = hexidecimal number. ;
; DS:SI points to byte after string. ;
; If (ZF) = 1 -- BX = 0 ;
; If (ZF) = 0 -- BX <> 0 ;
; ;
; AX, BX, CX, DI destroyed. ;
;----------------------------------------;
GET_NUMBER PROC NEAR
XOR BX,BX ;Start with zero.
PARSE_DELIMIT: LODSB ;Get a byte.
MOV DI,OFFSET DELIMITERS ;Is it a delimiter?
MOV CX,3
REPNZ SCASB
JZ PARSE_DELIMIT ;If yes, get next byte.
MOV CL,10
NEXT_NUMBER: XOR AH,AH ;Zero in high half.
CMP AL,CR ;Is byte a carriage return?
JZ NUMBER_END ;If yes, done.
CMP AL,"0" ;Is byte a number?
JB NUMBER_END
CMP AL,"9"
JA NUMBER_END ;If no, done.
SUB AL,"0" ;Else, convert to hex.
XCHG AX,BX ;Store in BX.
MUL CL ;Multiply accumulated by 10.
ADD BX,AX ;Add new number.
LODSB ;Next byte.
JMP SHORT NEXT_NUMBER
NUMBER_END: DEC SI ;Adjust pointer to delimiter.
OR BX,BX ;Set zero flag if results zero.
RET
GET_NUMBER ENDP
;--------------------------------------------------------;
; Parses off leading string delimiters. ;
; If carriage return encountered, jump directly to exit. ;
; ;
; INPUT ;
; DS:SI points to ASCII string. ;
; ;
; OUTPUT ;
; DS:SI points to first non-delimiting byte in string. ;
; ;
; All registers preserved. ;
;--------------------------------------------------------;
PARSE_LEADING PROC NEAR
LODSB ;Get a byte.
CMP AL,SPACE ;Is it a space char or below?
JA LEADING_END ;If no, done here.
CMP AL,CR ;Is it carriage return?
JNZ PARSE_LEADING ;If no, get next byte.
JMP SYNTAX_EXIT ;Else, immediate error exit.
LEADING_END: DEC SI ;Adjust pointer to string start.
RET
PARSE_LEADING ENDP
;------------------------------------------;
; Stores a filename in DOS DIR format. ;
; That is, filename, bytes, date and time. ;
; Results are printed to display. ;
; ;
; USES ;
; FILE_NAME TOUCH_DATE ;
; FILE_SIZE_LOW TOUCH_TIME ;
; FILE_SIZE_HIGH CR_LF ;
; ;
; CALLS ;
; STORE_WORD ;
; ;
; OUTPUT ;
; RESULTS = filename DIR style format. ;
; ;
; AX, BX, CX, DX, SI, DI destroyed. ;
;------------------------------------------;
DISPLAY_NAME PROC NEAR
MOV SI,OFFSET FILE_NAME ;Point to filename.
MOV DI,OFFSET RESULTS ;And storage area.
MOV AL,SPACE ;Initiate storage with spaces.
MOV CX,40
REP STOSB
MOV DI,OFFSET RESULTS ;Point to start of storage again.
MOV CX,12 ;Store 12 bytes of filename.
NEXT_STORE: LODSB ;Get a byte.
CMP AL,0 ;End of filename?
JZ END_STORE ;If yes, finish with blanks.
CMP AL,"." ;Is it the period?
JNZ STORE_BYTE ;If no, store.
SUB CX,3 ;Else store 3 spaces.
MOV AL,SPACE
REP STOSB
ADD CX,3
JMP SHORT NEXT_STORE ;Get next byte.
STORE_BYTE: STOSB ;Store byte.
LOOP NEXT_STORE ;Get next byte.
END_STORE: MOV AL,SPACE ;Pad balance with spaces.
REP STOSB
PUSH DI ;Save pointer.
ADD DI,8 ;Move to end of bytes field.
MOV DX,FILE_SIZE_LOW ;Retrieve high and low words
MOV AX,FILE_SIZE_HIGH ; of bytes.
MOV BX,10 ;Convert to decimal.
STD ;Reverse direction.
NEXT_SIZE: MOV CX,DX ;Low word in CX.
XOR DX,DX ;Zero in high half.
DIV BX ;Convert to decimal.
XCHG AX,CX ;Retrieve low word.
DIV BX
XCHG AX,DX ;Retrieve remainder.
ADD AL,"0" ;Convert to ASCII.
STOSB ;Store it.
MOV AX,CX ;Are we done?
OR CX,DX
JNZ NEXT_SIZE ;If no, divide again.
CLD ;Back to forward direction.
POP DI ;Retrieve pointer.
ADD DI,11 ;Move to date field.
DATE: MOV DX,TOUCH_DATE ;Retrieve date.
MOV AX,DX
MOV CL,5 ;Shift to lowest bits.
SHR AX,CL
AND AX,1111B ;Mask off all but month.
MOV CL,0FFH ;Flag as no leading zeros.
MOV CH,"-" ;Delimiting character.
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve date.
AND AX,11111B ;Mask off all but day.
XOR CL,CL ;Flag include leading zeros.
MOV CH,"-"
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve date for last time.
MOV CL,9
SHR AX,CL ;Mask off all but year.
ADD AX,80 ;Adjust to ASCII.
CMP AX,100 ;Past year 2000?
JB DISPLAY_DATE ;If no, display. Else, adjust for
SUB AX,100 ; next century. (Planning ahead!)
DISPLAY_DATE: XOR CL,CL ;Display leading zeros.
MOV CH,SPACE
CALL STORE_WORD ;Store it.
TIME: INC DI ;Move to time field.
MOV DX,TOUCH_TIME ;Retrieve time.
MOV AX,DX
MOV CL,11 ;Shift to hours bits.
SHR AX,CL
PUSH AX
CMP AX,12 ;Past noon?
JBE MERIDIAN
SUB AX,12 ;If yes, adjust.
MERIDIAN: CMP AX,0 ;Midnight?
JNZ NOT_MIDNIGHT
MOV AX,12 ;If yes, adjust.
NOT_MIDNIGHT: MOV CL,0FFH ;Suppress leading zeros.
MOV CH,":"
CALL STORE_WORD ;Store it.
MOV AX,DX ;Retrieve time.
MOV CL,5 ;Shift to minutes bits.
SHR AX,CL
AND AX,111111B ;Mask off all but minutes.
XOR CL,CL
POP DX ;Retrieve hours.
MOV CH,"p" ;Assume PM.
CMP DX,12 ;Is it PM?
JAE PM
MOV CH,"a" ;If no, AM.
PM: CALL STORE_WORD ;Store it.
MOV SI,OFFSET CR_LF ;Tack on carriage return
MOVSW ; linefeed.
MOVSB
MOV DX,OFFSET RESULTS ;Display results.
MOV AH,9
INT 21H
RET ;Done here.
DISPLAY_NAME ENDP
;----------------------------------------------;
; Converts a two byte hex number to decimal ;
; and stores the word followed by a delimiter. ;
; ;
; INPUT ;
; AX = hex number ;
; BL = 10 ;
; CH = delimiter character to store. ;
; CL = 0 if zeros are to be stored. ;
; CL = -1 if leading zeros ignored. ;
; ES:DI points to storage. ;
; ;
; OUTPUT ;
; ES:DI points to next storage location. ;
; ;
; AX destroyed. ;
;----------------------------------------------;
STORE_WORD PROC NEAR
DIV BL ;Divide by ten.
ADD AX,"00" ;Convert to ASCII.
CMP CL,0 ;Are we to display leading zero?
JZ STORE_IT ;If yes, store as is.
CMP AL,"0" ;Is it a leading zero?
JNZ STORE_IT ;If no, store it.
MOV AL,SPACE ;Else, store a space.
STORE_IT: STOSW
MOV AL,CH ;Store delimiter character also.
STOSB
RET
STORE_WORD ENDP
;--------------------------------------------------------------------------;
; String storage at end of code to avoid all those zeros in Basic listing. ;
;--------------------------------------------------------------------------;
CURRENT_DIR LABEL BYTE
WORKING_DIR EQU CURRENT_DIR + 68
RESULTS EQU WORKING_DIR + 68
_TEXT ENDS
END START